home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / telecomm / sticpsrc.lzh / SOURCE.ARC / NRCMD.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-05-10  |  23.6 KB  |  1,076 lines

  1. /* NET/ROM user command processing */
  2.  
  3. #include <stdio.h>
  4. #include "global.h"
  5. #include "mbuf.h"
  6. #include "ax25.h"
  7. #include "timer.h"
  8. #include "netrom.h"
  9. #include "iface.h"
  10. #include "lapb.h"
  11. #include "cmdparse.h"
  12. #include <ctype.h>
  13.  
  14. static int dointerface(),dobcnodes(),donodetimer(),donrnodes(),donrroute(),
  15.     donrrts(),doobsotimer(),doparam(),donodefilter(),donrstat(),dotcpip(),
  16.     donrexclude(),donrinfo(),donrusers();
  17.  
  18. static struct cmds nrcmds[] = {
  19.     "bcnodes",    dobcnodes,    2,    "<interface>",    NULLCHAR,
  20.     "exclude",    donrexclude,    0,    NULLCHAR,    NULLCHAR,
  21.     "info",        donrinfo,    0,    NULLCHAR,    NULLCHAR,
  22.     "interface",    dointerface,    4,
  23.                 "<interface> <alias> <quality> [lap|uplink]",NULLCHAR,
  24.     "nodefilter",    donodefilter,    0,    NULLCHAR,    NULLCHAR,
  25.     "nodes",    donrnodes,    0,    NULLCHAR,    NULLCHAR,
  26.     "nodetimer",    donodetimer,    0,    NULLCHAR,    NULLCHAR,
  27.     "obsotimer",    doobsotimer,    0,    NULLCHAR,    NULLCHAR,
  28.     "param",    doparam,    2,    "3|4 <params>", NULLCHAR,
  29.     "route",    donrroute,    0,    NULLCHAR,    NULLCHAR,
  30.     "routes",    donrrts,    0,    NULLCHAR,    NULLCHAR,
  31. #ifdef NETROM4
  32.     "status",    donrstat,    0,    NULLCHAR,    NULLCHAR,
  33. #endif
  34.     "tcpip",    dotcpip,    0,    NULLCHAR,
  35.                     "normal|link|broadcast|ignore [alias]",
  36. #ifdef NETROM4
  37.     "users",    donrusers,    0,    NULLCHAR,    NULLCHAR,
  38. #endif
  39.     NULLCHAR,    NULLFP,        0,
  40.         "?subcommands",
  41.     NULLCHAR
  42. };
  43.  
  44. char nr_savename[80] = "";        /* filename for route save */
  45. char nr_infname[80] = "";        /* filename for INFO output */
  46. #ifdef NETROM4
  47. struct interface *nr_lap = NULLIF;    /* Local Access Point interface */
  48. #endif
  49.  
  50. struct timer nodetimer;            /* timer for nodes broadcasts */
  51. static struct timer obsotimer;        /* timer for aging routes */
  52.  
  53. static char nonetrom[] = "Interface \"%s\" not for NET/ROM\n";
  54. static char baddest[] = "Bad destination callsign\n";
  55. static char badneigh[] = "Bad neighbor callsign\n";
  56. static char cr[] = "\r";
  57.  
  58. /* Command multiplexer */
  59. donetrom(argc,argv)
  60. int argc;
  61. char *argv[];
  62. {
  63.     return subcmd(nrcmds,argc,argv);
  64. }
  65.  
  66. static int dorouteadd(),doroutedrop(),dorouteinfo(),doroutesave();
  67.  
  68. static struct cmds routecmds[] = {
  69.     "add",    dorouteadd,    7,
  70.         "<dest> <alias> <quality> <obso> <interface> <neighbor>",
  71.         "add failed",
  72.     "drop", doroutedrop,    4,
  73.         "<destination>|* <interface> <neighbor>",
  74.         "drop failed",
  75.     "info", dorouteinfo,    2,
  76.         "<destination>",NULLCHAR,
  77.     "save", doroutesave,    0,
  78.         "[<filename>]",NULLCHAR,
  79.     NULLCHAR,    NULLFP, 0,
  80.         "?subcommands",
  81.         NULLCHAR
  82. };
  83.  
  84. /* Route command multiplexer */
  85. static
  86. donrroute(argc,argv)
  87. int argc;
  88. char *argv[];
  89. {
  90.     if (argc < 2) {
  91.         doroutedump(NULLBUFP,0,1);
  92.         return 0;
  93.     }
  94.     return subcmd(routecmds,argc,argv);
  95. }
  96.  
  97. /* format alias:call in a static buffer */
  98. char *
  99. nr_fmtcall (rp)
  100. struct nrroute_tab *rp;
  101. {
  102.     static char buf[20];
  103.     char *cp;
  104.  
  105.     strcpy(buf,rp->alias);
  106.     /* remove trailing spaces */
  107.     if ((cp = index(buf,' ')) == NULLCHAR)
  108.         cp = &buf[strlen(buf)];
  109.     if (cp != buf)        /* don't include colon for null alias */ 
  110.         *cp++ = ':';
  111.     pax25(cp,&rp->call);
  112.     return buf;
  113. }
  114.  
  115. /* find out if an active crosslink exists to some neigbor */
  116. /* return it's axp, or NULLAX25 */
  117. static struct ax25_cb *
  118. nrcrosslink (np)
  119. struct nrnbr_tab *np;
  120. {
  121.     struct ax25_cb *find_ax25();
  122.     struct ax25_addr neighbor,*nr_scall();
  123.  
  124.     getaxaddr(&neighbor,np->call);
  125.  
  126.     return find_ax25(&neighbor,nr_scall(np->interface));
  127. }
  128.  
  129. /* Dump a list of known routes */
  130. /* also called from the NODES command of NET/ROM level 7 */
  131. doroutedump(bpp,hide,ext)
  132.     struct mbuf **bpp;        /* append to mbuf if non-NULL */
  133.     int hide;            /* hide #ALIAS nodes */
  134.     int ext;            /* extended listing (includes route) */
  135. {
  136.     register struct nrroute_tab *rp,*srp;
  137.     struct nrroute_tab *sortp = NULLNRRTAB;
  138.     struct nrroute_tab **prev;
  139.     int i,j;
  140.     char line[80],buf[20],tmp[10];
  141.  
  142.     if(ext){            /* put header above extended listing */
  143.         strcpy(line,"Call      Alias  Routing       Interf  Call      Alias  Routing       Interf");
  144.         if(bpp != NULLBUFP){
  145.         strcat(line,cr);
  146.         append(bpp,qstring(line));
  147.         } else
  148.         printf("%s\n",line);
  149.     }
  150.  
  151.     line[0] = '\0';
  152.  
  153.     /* first pass: every route is put in a sorted list */
  154.     for (i = 0; i < NRNUMCHAINS; i++)
  155.         for (rp = nrroute_tab[i]; rp != NULLNRRTAB; rp = rp->next) {
  156.         if(hide && rp->alias[0] == '#')
  157.             continue;        /* ignore #ALIAS nodes */
  158.  
  159.         /* insert this one in the list at the proper position */
  160.         for (srp = sortp,prev = &sortp; srp != NULLNRRTAB;
  161.              prev = &srp->sort, srp = srp->sort){
  162.             /* compare srp->call and rp->call */
  163.             for (j = 0; j < ALEN; j++)
  164.             if (srp->call.call[j] != rp->call.call[j])
  165.                 break;
  166.             if (j < ALEN){
  167.             if (uchar(srp->call.call[j]) > uchar(rp->call.call[j]))
  168.                 break;
  169.             } else {
  170.             if ((srp->call.ssid & SSID) > (rp->call.ssid & SSID))
  171.                 break;
  172.             }
  173.         }
  174.         rp->sort = srp;
  175.         *prev = rp;
  176.         }
  177.  
  178.     /* second pass: the routes are printed in sorted list order */
  179.     for (rp = sortp; rp != NULLNRRTAB; rp = rp->sort) {
  180.         if(!ext){
  181.         sprintf(line + strlen(line),"%-16s ",nr_fmtcall(rp));
  182.         } else {
  183.         pax25(tmp,&rp->call);
  184.         sprintf(line + strlen(line),"%-10s%-7s",tmp,rp->alias);
  185.         if (rp->routes == NULLNRBIND){
  186.             sprintf(line + strlen(line),"%-22s","no route");
  187.         } else {
  188.             if(addreq(&rp->call,rp->routes->via->call)){
  189.             strcpy(buf,"direct");
  190.             } else {
  191.             pax25(tmp,rp->routes->via->call);
  192.             sprintf(buf,"via %-9s",tmp);
  193.             }
  194.             sprintf(line + strlen(line),"%-13s %-8s",
  195.                 buf,rp->routes->via->interface->name);
  196.         }
  197.         }
  198.         if (strlen(line) > 65) {
  199.         if(bpp != NULLBUFP){
  200.             strcat(line,cr);
  201.             append(bpp,qstring(line));
  202.         } else
  203.             printf("%s\n",line);
  204.         line[0] = '\0';
  205.         }
  206.     }
  207.  
  208.     if (line[0])
  209.         if(bpp != NULLBUFP){
  210.         strcat(line,cr);
  211.         append(bpp,qstring(line));
  212.         } else
  213.         printf("%s\n",line);
  214.  
  215.     return 0;
  216. }
  217.  
  218. /* print detailed information on an individual route */
  219. static
  220. dorouteinfo(argc,argv)
  221. int argc;
  222. char *argv[];
  223. {
  224.     register struct nrroute_tab *rp;
  225.     struct ax25_addr dest;
  226.  
  227.     if (setcall(&dest,argv[1]) < 0) {
  228.         printf(baddest);
  229.         return -1;
  230.     }
  231.  
  232.     if ((rp = find_nrroute(&dest)) == NULLNRRTAB) {
  233.         printf("no such route\n");
  234.         return -1;
  235.     }
  236.  
  237.     printf("CP Qual Obso Interf Neighbor     Node: ");
  238.     nrrouteinfo(NULLBUFP,rp);
  239.     return 0;
  240. }
  241.  
  242. /* show route info for some callsign */
  243. /* also called from the NODES command of NET/ROM level 7 */
  244. nrrouteinfo (bpp,rp)
  245. struct mbuf **bpp;            /* append to this mbuf if non-null */
  246. register struct nrroute_tab *rp;
  247.  
  248. {
  249.     register struct nr_bind *bp;
  250.     register struct nrnbr_tab *np;
  251.     char neighbor[60];
  252.     char line[80];
  253.  
  254.     strcpy(line,nr_fmtcall(rp));
  255.     if(bpp != NULLBUFP){
  256.         strcat(line,cr);
  257.         append(bpp,qstring(line));
  258.     } else
  259.         printf("%s\n",line);
  260.  
  261.     for (bp = rp->routes; bp != NULLNRBIND; bp = bp->next) {
  262.         np = bp->via;
  263.         psax25(neighbor,np->call);
  264.         sprintf(line,"%c%c  %3d  %3d %-6s %s",
  265.             (nrcrosslink(np) != NULLAX25 ? '>' : ' '),
  266.             (bp->flags & NRB_PERMANENT ? 'P' : ' '),
  267.             bp->quality,bp->obsocnt,
  268.             np->interface->name,
  269.             neighbor);
  270.  
  271.         if(bpp != NULLBUFP){
  272.         strcat(line,cr);
  273.         append(bpp,qstring(line));
  274.         } else
  275.         printf("%s\n",line);
  276.     }
  277. }
  278.  
  279. /* show routes to NET/ROM neighbors */
  280. /* also called from the ROUTES command of NET/ROM level 7 */
  281. nrrtsdump (bpp)
  282. struct mbuf **bpp;            /* append to this mbuf if non-null */
  283. {
  284.     struct nrnbr_tab *np;
  285.     int i;
  286.     char tmp[60];
  287.     char line[80];
  288.  
  289.     for (i = 0; i < NRNUMCHAINS; i++)
  290.         for (np = nrnbr_tab[i]; np != NULLNTAB; np = np->next){
  291.         psax25(tmp,np->call);
  292.         sprintf(line,"%c %-6s %3d %3d %-9s",
  293.             (nrcrosslink(np) != NULLAX25 ? '>' : ' '),
  294.             np->interface->name,
  295.             np->interface->nriface->quality,
  296.             np->refcnt,tmp);
  297.  
  298.         if (np->failcnt != 0) {
  299.             sprintf(tmp,"  (%d link failure%s)",
  300.             np->failcnt,(np->failcnt != 1)? "s":"");
  301.             strcat(line,tmp);
  302.         }
  303.  
  304.         if(bpp != NULLBUFP){
  305.             strcat(line,cr);
  306.             append(bpp,qstring(line));
  307.         } else
  308.             printf("%s\n",line);
  309.         }
  310. }
  311.  
  312. /* set filename for INFO output */
  313. static
  314. donrinfo(argc,argv)
  315. int argc;
  316. char *argv[];
  317. {
  318.     if (argc < 2)
  319.         printf("%s\n",nr_infname);
  320.     else
  321.         strcpy(nr_infname,argv[1]);
  322.  
  323.     return 0;
  324. }
  325.  
  326. /* save routing info, or set filename for saves */
  327. static
  328. doroutesave(argc,argv)
  329. int argc;
  330. char *argv[];
  331. {
  332.     if (argc < 2)
  333.         nr_routesave();
  334.     else
  335.         strcpy(nr_savename,argv[1]);
  336.  
  337.     return 0;
  338. }
  339.  
  340. /* display nodes like in NET/ROM "nodes" command */
  341. static
  342. donrnodes(argc,argv)
  343. int argc;
  344. char *argv[];
  345. {
  346.     int hide = 0;
  347.  
  348.     if (argc < 2 || argv[1][0] != '*')
  349.         hide = 1;
  350.  
  351.     doroutedump(NULLBUFP,hide,0);
  352.     return 0;
  353. }
  354.  
  355. /* display routes like in NET/ROM "routes" command */
  356. static
  357. donrrts(argc,argv)
  358. int argc;
  359. char *argv[];
  360. {
  361.     nrrtsdump(NULLBUFP);
  362.     return 0;
  363. }
  364.  
  365. /* convert a null-terminated alias name to a blank-filled */
  366. /* version. It is no longer upcased. Return -1 on failure. */
  367. static int
  368. putalias(to,from)
  369. register char *to,*from;
  370. {
  371.     int len,i;
  372.  
  373.     if ((len = strlen(from)) > ALEN) {
  374.         printf("alias too long - six characters max\n");
  375.         return -1;
  376.     }
  377.  
  378.     for (i = 0; i < ALEN; i++) {
  379.         if (i < len) {
  380.         if (*from < ' ' || *from >= 127) {
  381.             printf("illegal char in alias\n");
  382.             return -1;
  383.         }
  384.  
  385.         *to++ = *from++;
  386.         } else
  387.         *to++ = ' ';
  388.     }
  389.  
  390.     *to = '\0';
  391.     return 0;
  392. }
  393.  
  394. /* Add a route */
  395. /* Usage: netrom route add <dest> <alias> <quality> <obso> <interface> <neighbor> */
  396. static
  397. dorouteadd(argc,argv)
  398. int argc;
  399. char *argv[];
  400. {
  401.     char alias[7];
  402.     struct ax25_addr dest;
  403.     unsigned quality,obsocnt,perm;
  404.     char neighbor[AXALEN * 3];
  405.     register struct interface *ifp;
  406.     int naddr;
  407.  
  408.     /* format destination callsign */
  409.     if (setcall(&dest,argv[1]) < 0) {
  410.         printf(baddest);
  411.         return -1;
  412.     }
  413.  
  414.     /* format alias (putalias prints error message if necessary) */
  415.     if (putalias(alias,argv[2]) < 0)
  416.         return -1;
  417.  
  418.     /* get and check quality value */
  419.     if ((quality = atoi(argv[3])) > 255) {
  420.         printf("maximum route quality is 255\n");
  421.         return -1;
  422.     }
  423.  
  424.     /* get and check obsoletion count value. 0 means permanent. */
  425.     if ((obsocnt = atoi(argv[4])) > 255) {
  426.         printf("maximum obsoletion count is 255\n");
  427.         return -1;
  428.     }
  429.  
  430.     if (obsocnt == 0){
  431.         perm = 1;
  432.         obsocnt = obso_init;
  433.     } else {
  434.         perm = 0;
  435.     }
  436.  
  437.     /* find interface */
  438.     if ((ifp = ifunit(argv[5])) == NULLIF)
  439.         return -1;
  440.     if (ifp->nriface == NULLNRIFACE){
  441.         printf(nonetrom,argv[5]);
  442.         return -1;
  443.     }
  444.  
  445.     /* make sure no more than 2 digis */
  446.     naddr = argc - 6;
  447.     if (naddr > 3) {
  448.         printf("no more than 2 digipeaters for a NET/ROM neighbor\n");
  449.         return -1;
  450.     }
  451.  
  452.     /* format neighbor address string */
  453.     setpath(neighbor,&argv[6],naddr);
  454.  
  455.     if (nr_rt_add(alias,&dest,ifp,quality,obsocnt,neighbor,perm) < 0)
  456.         return -1;
  457.  
  458.     return 0;
  459. }
  460.  
  461.  
  462. /* drop a route */
  463. /* Usage: netrom route drop <destination> <interface> <neighbor> */
  464. static
  465. doroutedrop(argc,argv)
  466. int argc;
  467. char *argv[];
  468. {
  469.     struct ax25_addr *dp,dest,neighbor;
  470.     register struct interface *ifp;
  471.  
  472.     /* check for * = all destinations via this neighbor */
  473.     if (!strcmp(argv[1],"*"))
  474.         dp = NULLAXADDR;            /* NULL to nr_rt_drop */
  475.     else
  476.         /* format destination callsign */
  477.         if (setcall(dp = &dest,argv[1]) < 0) {
  478.         printf(baddest);
  479.         return -1;
  480.         }
  481.     /* find interface */
  482.     if ((ifp = ifunit(argv[2])) == NULLIF)
  483.         return -1;
  484.     if (ifp->nriface == NULLNRIFACE){
  485.         printf(nonetrom,argv[2]);
  486.         return -1;
  487.     }
  488.     if (setcall(&neighbor,argv[3]) < 0) {
  489.         printf(badneigh);
  490.         return -1;
  491.     }
  492.  
  493.     return nr_rt_drop(dp,&neighbor,ifp);
  494. }
  495.  
  496. /* route save routine. creates file with netrom route add commands... */
  497. static
  498. nr_routesave()
  499. {
  500.     FILE *savefile;
  501.     register struct nrroute_tab *rp;
  502.     register struct nr_bind *bp;
  503.     int i;
  504.     char *p;
  505.     char tmp1[10],tmp2[10],tmp3[60];
  506.  
  507.     if (nr_savename[0] == '\0')
  508.         return;
  509.  
  510.     if ((savefile = fopen(nr_savename,"w")) == NULLFILE)
  511.         return;
  512.  
  513.     fprintf(savefile,"# NET/ROM routes (auto-saved):\n");
  514.     for (i = 0; i < NRNUMCHAINS; i++) {
  515.         for (rp = nrroute_tab[i]; rp != NULLNRRTAB; rp = rp->next) {
  516.         pax25(tmp1,&rp->call);
  517.         strcpy(tmp2,rp->alias);
  518.         for (p = tmp2; *p != '\0'; p++)
  519.             if (*p == ' ')
  520.             *p = '\0';
  521.  
  522.         for (bp = rp->routes; bp != NULLNRBIND; bp = bp->next) {
  523.             psax25(tmp3,bp->via->call);
  524.             fprintf(savefile,"netrom route add %s '%s' %d %d %s %s\n",
  525.                 tmp1,tmp2,bp->quality,bp->obsocnt,
  526.                 bp->via->interface->name,tmp3);
  527.         }
  528.         }
  529.     }
  530.  
  531.     fclose(savefile);
  532. }
  533.  
  534. /* display or set netrom level 3 or 4 parameters */
  535. static int
  536. doparam(argc,argv)
  537. int argc;
  538. char *argv[];
  539. {
  540.     switch(argv[1][0])
  541.     {
  542.     case '3':
  543.     case 'n':
  544.         if(argc == 2){
  545.         printf("Autofloor=%u Obso_init=%u Obso_minbc=%u TTL=%u Maxroutes=%u Maxqueue=%u Maxfail=%u\n",
  546.                nr_autofloor,obso_init,obso_minbc,nr_ttl,nr_maxroutes,nr_maxqueue,nr_maxfail);
  547.         return 0;
  548.         }
  549.         if(argc > 2)
  550.         nr_autofloor = atoi(argv[2]);
  551.         if(argc > 3)
  552.         obso_init = atoi(argv[3]);
  553.         if(argc > 4)
  554.         obso_minbc = atoi(argv[4]);
  555.         if(argc > 5)
  556.         nr_ttl = atoi(argv[5]);
  557.         if(argc > 6)
  558.         nr_maxroutes = atoi(argv[6]);
  559.         if(argc > 7)
  560.         nr_maxqueue = atoi(argv[7]);
  561.         if(argc > 8)
  562.         nr_maxfail = atoi(argv[8]);
  563.         break;
  564.  
  565.     case '4':
  566.     case 't':
  567. #ifdef NETROM4
  568.         if(argc == 2){
  569.         printf("Timeout=%u Tries=%u Ackdelay=%u Busydelay=%u Window=%u Backlog=%u Inactive=%u\n",
  570.                nr_trtimeout,nr_trtries,nr_trackdelay,nr_trbusdelay,
  571.                nr_trwindow,nr_trbacklog,nr_noactive);
  572.         return 0;
  573.         }
  574.         if(argc > 2)
  575.         nr_trtimeout = atoi(argv[2]);
  576.         if(argc > 3)
  577.         nr_trtries = atoi(argv[3]);
  578.         if(argc > 4)
  579.         nr_trackdelay = atoi(argv[4]);
  580.         if(argc > 5)
  581.         nr_trbusdelay = atoi(argv[5]);
  582.         if(argc > 6)
  583.         nr_trwindow = atoi(argv[6]);
  584.         if(argc > 7)
  585.         nr_trbacklog = atoi(argv[7]);
  586.         if(argc > 8)
  587.         nr_noactive = atoi(argv[8]);
  588. #endif
  589.         break;
  590.  
  591.     default:
  592.         printf("level must be 3 (network) or 4 (transport)\n");
  593.         return -1;
  594.     }
  595.     return 0;
  596. }
  597.  
  598. /* Display or change netrom excluded node callsigns
  599.  * usage:
  600.  * netrom exclude <callsign> [d]
  601.  * netrom exclude
  602.  */
  603. static
  604. donrexclude(argc,argv)
  605. int argc;
  606. char *argv[];
  607. {
  608.     register struct ax25_call *axc;
  609.     struct ax25_addr call;
  610.     int i,n;
  611.     char tmp[10];
  612.  
  613.     if(argc < 2){
  614.         for (i = n = 0; i < NHASH; i++){
  615.         for (axc = nr_excl[i]; axc != NULLAXCALL; axc = axc->next){
  616.             pax25(tmp,&axc->addr);
  617.             printf("%-6s%s",tmp,(++n % 8) == 0? "\n":"  ");
  618.         }
  619.         }
  620.         if ((n % 8) != 0)
  621.         printf("\n");
  622.         return 0;
  623.     }
  624.  
  625.     if(setcall(&call,argv[1]) < 0){
  626.         printf("Usage: netrom exclude <callsign> [d]\n");
  627.         return -1;
  628.     }
  629.  
  630.     call.ssid = 0;            /* always use the -0 SSID */
  631.  
  632.     if(argc > 2 && !strcmp(argv[2],"d")){
  633.         if((axc = find_axcall(nr_excl,&call)) != NULLAXCALL){
  634.             del_axcall(nr_excl,axc);
  635.             return 0;
  636.         } else {
  637.             pax25(tmp,&call);
  638.             printf("%s not in exclude list\n",tmp);
  639.             return -1;
  640.         }
  641.     }
  642.  
  643.     if((axc = cr_axcall(nr_excl,&call)) == NULLAXCALL)
  644.         return -1;
  645.  
  646.     axc->flags = 0;
  647.     return 0;
  648. }
  649.  
  650. #ifdef NETROM4
  651. /* show status of NET/ROM transport-layer connections */
  652. static int
  653. donrstat(argc,argv)
  654. int argc;
  655. char *argv[];
  656. {
  657.     int idx;
  658.     register struct nr_circ *circ;
  659.     char user[10],node[10];
  660.  
  661.     printf("Local  Remote User      @Node     S Wi TxS TxA RxS C S R Tx Rx TrnT AckT NoaT\n");
  662.  
  663.     for (idx = 0; idx < NR4NUMCIRC; idx++)
  664.         if ((circ = nr_circ[idx]) != NULLNRCIRC) {
  665.         pax25(user,&circ->suser);
  666.         pax25(node,&circ->dnode);
  667.         printf("%2d/%-3d %2d/%-3d %-9s %-9s %c %2d %3d %3d %3d %d %d %d %2d %2d",
  668.             circ->my.index,uchar(circ->my.id),
  669.             circ->your.index,uchar(circ->your.id),
  670.             user,node,
  671.             ((circ->state < 4)? "RPCD"[circ->state] : '?'),
  672.             circ->window,circ->txseq,circ->txack,circ->rxseq,
  673.             circ->r_choked,circ->s_choked,circ->retries,
  674.             len_q(circ->txq),len_q(circ->rxq));
  675.         if (run_timer(&circ->trtimer))
  676.             printf("%5ld",TICK2SEC(circ->trtimer.start - circ->trtimer.count));
  677.         else
  678.             printf(" stop");
  679.         if (run_timer(&circ->acktimer))
  680.             printf("%5ld",TICK2SEC(circ->acktimer.start - circ->acktimer.count));
  681.         else
  682.             printf(" stop");
  683.         if (run_timer(&circ->noacttim))
  684.             printf("%5ld\n",TICK2SEC(circ->noacttim.start - circ->noacttim.count));
  685.         else
  686.             printf(" stop\n");
  687.         }
  688.  
  689.     return 0;
  690. }
  691.  
  692. /* show users of NET/ROM (like "users" command on the NR7 interpreter) */
  693. static int
  694. donrusers(argc,argv)
  695. int argc;
  696. char *argv[];
  697. {
  698.     nruserdump(NULLBUFP);        /* show users to screen */
  699.     return 0;
  700. }
  701. #endif
  702.  
  703. /* set and display the TCP/IP netrom node special handling */
  704. static int
  705. dotcpip(argc,argv)
  706. int argc;
  707. char *argv[];
  708. {
  709.     if (argc == 1){
  710.         printf("Non-%s node handling: ",nr_aliasip);
  711.         switch (nr_tcpip)
  712.         {
  713.         case NRT_NORM:
  714.         printf("normal\n");
  715.         break;
  716.  
  717.         case NRT_ILNK:
  718.         printf("broadcast on interlink\n");
  719.         break;
  720.  
  721.         case NRT_NOBR:
  722.         printf("no broadcast\n");
  723.         break;
  724.  
  725.         case NRT_IGN:
  726.         printf("ignore in broadcast\n");
  727.         break;
  728.         }
  729.     } else {
  730.         switch (tolower(argv[1][0]))
  731.         {
  732.         case 'n':
  733.         nr_tcpip = NRT_NORM;
  734.         break;
  735.  
  736.         case 'l':
  737.         nr_tcpip = NRT_ILNK;
  738.         break;
  739.  
  740.         case 'b':
  741.         nr_tcpip = NRT_NOBR;
  742.         break;
  743.  
  744.         case 'i':
  745.         nr_tcpip = NRT_IGN;
  746.         break;
  747.  
  748.         default:
  749.         return -1;
  750.         }
  751.  
  752.         if (argc > 2)
  753.         if (putalias(nr_aliasip,argv[2]) != 0)
  754.             return 1;
  755.     }
  756.  
  757.     return 0;
  758. }
  759.  
  760. /* make an interface available to NET/ROM */
  761. static int
  762. dointerface(argc,argv)
  763. int argc;
  764. char *argv[];
  765. {
  766.     register struct interface *ifp;
  767.  
  768.     if (nr_interface == NULLIF) {
  769.         printf("Attach netrom interface first\n");
  770.         return 1;
  771.     }
  772.  
  773.     if((ifp = ifunit(argv[1])) == NULLIF)
  774.         return 1;
  775.  
  776.     if (!(ifp->flags & IF_AX25)) {
  777.         printf("Must be an AX.25 interface\n");
  778.         return 1;
  779.     }
  780.  
  781.     if (ifp->nriface != NULLNRIFACE){
  782.         printf("Interface \"%s\" is already registered\n",argv[1]);
  783.         return 1;
  784.     }
  785.  
  786.     if ((ifp->nriface = (struct nriface *) calloc(1,sizeof(struct nriface)))
  787.         == NULLNRIFACE)
  788.         return -1;
  789.  
  790.     if (putalias(ifp->nriface->alias,argv[2]) < 0)
  791.         return 1;
  792.  
  793.     ifp->nriface->quality = uchar(atoi(argv[3]));
  794.  
  795. #ifdef NETROM4
  796.     if (argc > 4)            /* a fourth arg given? */
  797.         switch (argv[4][0]) {
  798.         case 'l':            /* lap */
  799.         case 'L':
  800.         nr_lap = ifp;        /* this iface is the LAP */
  801.                     /* this implies it has uplink */
  802.         case 'u':            /* uplink */
  803.         case 'U':
  804.         ifp->nriface->uplink = 1;
  805.         break;
  806.         }
  807. #endif
  808.  
  809.     return 0;
  810. }
  811.  
  812. /* Broadcast nodes list on named interface. */
  813.  
  814. static int
  815. dobcnodes(argc,argv)
  816. int argc;
  817. char *argv[];
  818. {
  819.     register struct interface *ifp;
  820.  
  821.     if ((ifp = ifunit(argv[1])) == NULLIF)
  822.         return -1;
  823.     if (ifp->nriface == NULLNRIFACE){
  824.         printf(nonetrom,argv[1]);
  825.         return -1;
  826.     }
  827.  
  828.     nr_bcnodes(ifp);
  829.     return 0;
  830. }
  831.  
  832. /* Set outbound node broadcast interval */
  833. static int
  834. donodetimer(argc,argv)
  835. int argc;
  836. char *argv[];
  837. {
  838.     int donodetick();
  839.  
  840.     if(argc < 2){
  841.         printf("%lu/%lu\n", TICK2SEC(nodetimer.start - nodetimer.count),
  842.                 TICK2SEC(nodetimer.start));
  843.         return 0;
  844.     }
  845.     stop_timer(&nodetimer);            /* in case it's already running */ 
  846.     nodetimer.func = (void (*)())donodetick;/* what to call on timeout */
  847.     nodetimer.arg = NULLCHAR;        /* dummy value */
  848.     nodetimer.start = SEC2TICK(atol(argv[1]));    /* set timer duration */
  849.     nodetimer.count = 0;            /* in case 0 time specified */
  850.  
  851.     start_timer(&nodetimer);        /* and fire it up */
  852.     return 0;
  853. }
  854.  
  855. static int
  856. donodetick()
  857. {
  858.     register struct interface *ifp;
  859.  
  860.     for (ifp = ifaces; ifp != NULLIF; ifp = ifp->next)
  861.         if (ifp->nriface != NULLNRIFACE)
  862.             nr_bcnodes(ifp);
  863.  
  864.     /* Restart timer */
  865.     start_timer(&nodetimer);
  866. }
  867.  
  868. /* Set timer for aging routes */
  869. static int
  870. doobsotimer(argc,argv)
  871. int argc;
  872. char *argv[];
  873. {
  874.     extern int doobsotick();
  875.  
  876.     if(argc < 2){
  877.         printf("%lu/%lu\n", TICK2SEC(obsotimer.start - obsotimer.count),
  878.                 TICK2SEC(obsotimer.start));
  879.         return 0;
  880.     }
  881.     stop_timer(&obsotimer);            /* just in case it's already running */
  882.     obsotimer.func = (void (*)())doobsotick;/* what to call on timeout */
  883.     obsotimer.arg = NULLCHAR;        /* dummy value */
  884.     if ((obsotimer.start = SEC2TICK(atol(argv[1]))) == 0)/* set timer duration */
  885.         obsotimer.start = SEC2TICK(3600L);
  886.  
  887.     start_timer(&obsotimer);        /* and fire it up */
  888.     return 0;
  889. }
  890.  
  891.  
  892. /* Go through the routing table,reducing the obsolescence count of
  893.  * non-permanent routes,and purging them if the count reaches 0
  894.  */
  895. static int
  896. doobsotick()
  897. {
  898.     register struct nrroute_tab *rp;
  899.     struct nrroute_tab *rpnext;
  900.     register struct nr_bind *bp;
  901.     struct nr_bind *bpnext;
  902.     int i;
  903.  
  904.     for (i = 0; i < NRNUMCHAINS; i++) {
  905.         for (rp = nrroute_tab[i]; rp != NULLNRRTAB; rp = rpnext) {
  906.         rpnext = rp->next;        /* save in case we free this route */
  907.         for (bp = rp->routes; bp != NULLNRBIND; bp = bpnext) {
  908.             bpnext = bp->next;        /* in case we free this binding */
  909.             if (bp->flags & NRB_PERMANENT)  /* don't age these */
  910.             continue;
  911.             if (--bp->obsocnt == 0)    /* time's up! */
  912.             nr_rnb_drop(rp,bp->via,bp); /* drop it */
  913.         }
  914.         }
  915.     }
  916.  
  917.     nr_routesave();            /* save changed state */
  918.     start_timer(&obsotimer);
  919. }
  920.  
  921.  
  922. static int donfadd(),donfdrop(),donfmode();
  923.  
  924. static struct cmds nfcmds[] = {
  925.     "add",    donfadd,    3,
  926.         "<neighbor> <interface>",
  927.         "add failed",
  928.     "drop",donfdrop,    3,
  929.         "<neighbor> <interface>",
  930.         "drop failed",
  931.     "mode",donfmode,    0,    NULLCHAR,    NULLCHAR,
  932.     NULLCHAR,    NULLFP,0,
  933.         "?subcommands",
  934.         NULLCHAR
  935. };
  936.  
  937. /* nodefilter command multiplexer */
  938. static
  939. donodefilter(argc,argv)
  940. int argc;
  941. char *argv[];
  942. {
  943.     if (argc < 2) {
  944.         donfdump();
  945.         return 0;
  946.     }
  947.     return subcmd(nfcmds,argc,argv);
  948. }
  949.  
  950. /* display a list of <callsign,interface> pairs from the filter
  951.  * list.
  952.  */
  953. static
  954. donfdump()
  955. {
  956.     int i,column = 1;
  957.     struct nrnf_tab *fp;
  958.     char buf[16];
  959.  
  960.     printf("Neighbor  Interface Neighbor  Interface Neighbor  Interface Neighbor  Interface\n");
  961.     for (i = 0; i < NRNUMCHAINS; i++)
  962.         for (fp = nrnf_tab[i]; fp != NULLNRNFTAB; fp = fp->next) {
  963.         pax25(buf,&fp->neighbor);
  964.         printf("%-9s %-8s%s",
  965.                buf,fp->interface->name,
  966.                (column++ == 4)? (column = 1,"\n"):"  ");
  967.         }
  968.  
  969.     if (column != 1)
  970.         printf("\n");
  971.  
  972.     return 0;
  973. }
  974.  
  975. /* add an entry to the filter table */
  976. static
  977. donfadd(argc,argv)
  978. int argc;
  979. char *argv[];
  980. {
  981.     struct ax25_addr neighbor;
  982.     struct interface *ifp;
  983.  
  984.     /* format callsign */
  985.     if (setcall(&neighbor,argv[1]) < 0) {
  986.         printf(badneigh);
  987.         return -1;
  988.     }
  989.  
  990.     /* find interface */
  991.     if ((ifp = ifunit(argv[2])) == NULLIF)
  992.         return -1;
  993.     if (ifp->nriface == NULLNRIFACE){
  994.         printf(nonetrom,argv[2]);
  995.         return -1;
  996.     }
  997.  
  998.     return nr_nfadd(&neighbor,ifp);
  999. }
  1000.  
  1001. /* drop an entry from the filter table */
  1002. static
  1003. donfdrop(argc,argv)
  1004. int argc;
  1005. char *argv[];
  1006. {
  1007.     struct ax25_addr neighbor;
  1008.     struct interface *ifp;
  1009.  
  1010.     /* format neighbor callsign */
  1011.     if (setcall(&neighbor,argv[1]) < 0) {
  1012.         printf(badneigh);
  1013.         return -1;
  1014.     }
  1015.  
  1016.     /* find interface */
  1017.     if ((ifp = ifunit(argv[2])) == NULLIF)
  1018.         return -1;
  1019.     if (ifp->nriface == NULLNRIFACE){
  1020.         printf(nonetrom,argv[2]);
  1021.         return -1;
  1022.     }
  1023.  
  1024.     return nr_nfdrop(&neighbor,ifp);
  1025. }
  1026.  
  1027. /* nodefilter mode subcommand */
  1028. static
  1029. donfmode(argc,argv)
  1030. int argc;
  1031. char *argv[];
  1032. {
  1033.     if (argc < 2) {
  1034.         printf("filter mode is ");
  1035.         switch (nr_nfmode) {
  1036.             case NRNF_NOFILTER:
  1037.                 printf("none\n");
  1038.                 break;
  1039.             case NRNF_REJECT:
  1040.                 printf("reject\n");
  1041.                 break;
  1042.             case NRNF_ACCEPT:
  1043.                 printf("accept\n");
  1044.                 break;
  1045.             case NRNF_EXCLUSIVE:
  1046.                 printf("exclusive\n");
  1047.                 break;
  1048.         }
  1049.         return 0;
  1050.     }
  1051.  
  1052.     switch (argv[1][0]) {
  1053.         case 'n':
  1054.         case 'N':
  1055.             nr_nfmode = NRNF_NOFILTER;
  1056.             break;
  1057.         case 'r':
  1058.         case 'R':
  1059.             nr_nfmode = NRNF_REJECT;
  1060.             break;
  1061.         case 'a':
  1062.         case 'A':
  1063.             nr_nfmode = NRNF_ACCEPT;
  1064.             break;
  1065.         case 'e':
  1066.         case 'E':
  1067.             nr_nfmode = NRNF_EXCLUSIVE;
  1068.             break;
  1069.         default:
  1070.             printf("modes are: none reject accept exclusive\n");
  1071.             return -1;
  1072.     }
  1073.  
  1074.     return 0;
  1075. }
  1076.